package com.sh.data.engine.job.admin.dao;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sh.data.engine.job.admin.core.model.XxlJobLog;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.*;
import java.util.stream.Collectors;

/**
 * job log
 *
 * @author xuxueli 2016-1-12 18:03:06
 */
@Mapper
public interface XxlJobLogDao extends BaseMapper<XxlJobLog> {

    // exist jobId not use jobGroup, not exist use jobGroup
    default List<XxlJobLog> pageList(
        int offset,
        int pagesize,
        int jobGroup,
        int jobId,
        Date triggerTimeStart,
        Date triggerTimeEnd,
        int logStatus) {
        QueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<XxlJobLog>();
        LambdaQueryWrapper<XxlJobLog> query =
            queryWrapper
                .lambda()
                .eq(jobId == 0 && jobGroup > 0, XxlJobLog::getJobGroup, jobGroup)
                .eq(jobId > 0, XxlJobLog::getJobId, jobId)
                .ge(Objects.nonNull(triggerTimeStart), XxlJobLog::getTriggerTime, triggerTimeStart)
                .le(Objects.nonNull(triggerTimeEnd), XxlJobLog::getTriggerTime, triggerTimeEnd)
                .eq(logStatus == 1, XxlJobLog::getHandleCode, 200)
                .and(
                    logStatus == 2,
                    wrapper ->
                        wrapper
                            .notIn(XxlJobLog::getTriggerCode, 0, 200)
                            .or(wrapper2 -> wrapper2.notIn(XxlJobLog::getHandleCode, 0, 200)))
                .and(
                    logStatus == 3,
                    wrapper ->
                        wrapper.eq(XxlJobLog::getTriggerCode, 200).eq(XxlJobLog::getHandleCode, 0))
                .orderByDesc(XxlJobLog::getTriggerTime);

        Page<XxlJobLog> xxlJobLogPage = selectPage(new Page<XxlJobLog>(offset, pagesize), query);
        return xxlJobLogPage.getRecords();
    }

    default Long pageListCount(
        int offset,
        int pagesize,
        int jobGroup,
        int jobId,
        Date triggerTimeStart,
        Date triggerTimeEnd,
        int logStatus) {
        LambdaQueryWrapper<XxlJobLog> queryWrapper = new QueryWrapper<XxlJobLog>().lambda();
        queryWrapper
            .eq(jobId == 0 && jobGroup > 0, XxlJobLog::getJobGroup, jobGroup)
            .eq(jobId > 0, XxlJobLog::getJobId, jobId)
            .ge(Objects.nonNull(triggerTimeStart), XxlJobLog::getTriggerTime, triggerTimeStart)
            .le(Objects.nonNull(triggerTimeEnd), XxlJobLog::getTriggerTime, triggerTimeEnd)
            .eq(logStatus == 1, XxlJobLog::getHandleCode, 200)
            .and(
                logStatus == 2,
                wrapper ->
                    wrapper
                        .notIn(XxlJobLog::getTriggerCode, 0, 200)
                        .or(wrapper2 -> wrapper2.notIn(XxlJobLog::getHandleCode, 0, 200)))
            .and(
                logStatus == 3,
                wrapper -> wrapper.eq(XxlJobLog::getTriggerCode, 200).eq(XxlJobLog::getHandleCode, 0))
            .orderByDesc(XxlJobLog::getTriggerTime);
        Page<XxlJobLog> xxlJobLogPage =
            this.selectPage(new Page<XxlJobLog>(offset, pagesize), queryWrapper);
        return xxlJobLogPage.getTotal();
    }

    default XxlJobLog load(long id) {
        return this.selectById(id);
    }

    default long save(XxlJobLog xxlJobLog) {
        return this.insert(xxlJobLog);
    }

    default int updateTriggerInfo(XxlJobLog xxlJobLog) {
        return this.updateById(xxlJobLog);
    }

    default int updateHandleInfo(XxlJobLog xxlJobLog) {
        // FIXME ERROR with line .eq(XxlJobLog::getId, xxlJobLog.getJobId()) -> xxlJobLog.getId()
        LambdaUpdateWrapper<XxlJobLog> updateWrapper =
            new UpdateWrapper<XxlJobLog>()
                .lambda()
                .eq(XxlJobLog::getId, xxlJobLog.getJobId())
                .set(XxlJobLog::getHandleTime, xxlJobLog.getHandleTime())
                .set(XxlJobLog::getHandleCode, xxlJobLog.getHandleCode())
                .set(XxlJobLog::getHandleMsg, xxlJobLog.getHandleMsg());
        return this.update(null, updateWrapper);
    }

    default int delete(int jobId) {
        LambdaQueryWrapper<XxlJobLog> wrapper =
            new QueryWrapper<XxlJobLog>().lambda().eq(XxlJobLog::getJobId, jobId);
        return this.delete(wrapper);
    }

    Map<String, Object> findLogReport(@Param("from") Date from, @Param("to") Date to);

    default void cleanRecord(Date cleanTime) {
        LambdaQueryWrapper<XxlJobLog> wrapper = new QueryWrapper<XxlJobLog>().lambda();
        wrapper.le(XxlJobLog::getTriggerTime, cleanTime);
        this.delete(wrapper);
    }

    default List<Long> findClearLogIds(
        int jobGroup, int jobId, Date clearBeforeTime, int clearBeforeNum, int pagesize) {
        List<Long> ids = new ArrayList();
        if (clearBeforeNum > 0) {
            LambdaQueryWrapper<XxlJobLog> wrapperIn = new QueryWrapper<XxlJobLog>().lambda();
            wrapperIn
                .eq(jobGroup > 0, XxlJobLog::getJobGroup, jobGroup)
                .eq(jobId > 0, XxlJobLog::getJobId, jobId)
                .orderByDesc(XxlJobLog::getTriggerTime);

            Page<XxlJobLog> xxlJobLogPage = selectPage(new Page<XxlJobLog>(0, pagesize), wrapperIn);
            List<XxlJobLog> xxlJobLogs = xxlJobLogPage.getRecords();
            ids = xxlJobLogs.stream().map(XxlJobLog::getId).collect(Collectors.toList());
        }
        LambdaQueryWrapper<XxlJobLog> wrapper = new QueryWrapper<XxlJobLog>().lambda();
        wrapper
            .eq(jobGroup > 0, XxlJobLog::getJobGroup, jobGroup)
            .eq(jobId > 0, XxlJobLog::getJobId, jobId)
            .le(Objects.nonNull(clearBeforeTime), XxlJobLog::getTriggerTime, clearBeforeTime)
            .notIn(clearBeforeNum > 0, XxlJobLog::getId, ids)
            .orderByAsc(XxlJobLog::getId)
            .last(String.format("LIMIT %d", pagesize));
        List<XxlJobLog> xxlJobLogs = this.selectList(wrapper);
        return xxlJobLogs.stream().map(XxlJobLog::getId).collect(Collectors.toList());
    }

    default int clearLog(List<Long> logIds) {
        return this.deleteBatchIds(logIds);
    }

    default List<Long> findFailJobLogIds(int pagesize) {
        LambdaQueryWrapper<XxlJobLog> wrapper = new QueryWrapper<XxlJobLog>().lambda();
        wrapper
            .notIn(XxlJobLog::getTriggerCode, 0, 200)
            .ne(XxlJobLog::getHandleCode, 200)
            .or(i -> i.ne(XxlJobLog::getHandleCode, 200))
            .eq(XxlJobLog::getAlarmStatus, 0)
            .orderByAsc(XxlJobLog::getId)
            .last(String.format("LIMIT %d", pagesize));
        List<XxlJobLog> xxlJobLogs = this.selectList(wrapper);
        return xxlJobLogs.stream().map(XxlJobLog::getId).collect(Collectors.toList());
    }

    default int updateAlarmStatus(long logId, int oldAlarmStatus, int newAlarmStatus) {
        LambdaUpdateWrapper<XxlJobLog> update = new UpdateWrapper<XxlJobLog>().lambda();
        update
            .eq(XxlJobLog::getId, logId)
            .eq(XxlJobLog::getAlarmStatus, oldAlarmStatus)
            .set(XxlJobLog::getAlarmStatus, newAlarmStatus);
        return this.update(null, update);
    }

    List<Long> findLostJobIds(@Param("losedTime") Date losedTime);

    default List<XxlJobLog> findRunningFlinkLogs(long jobInfoId) {
        LambdaQueryWrapper<XxlJobLog> wrapper = new QueryWrapper<XxlJobLog>().lambda();
        wrapper
            .eq(XxlJobLog::getJobId, jobInfoId)
            .eq(XxlJobLog::getTriggerCode, 200)
            .eq(XxlJobLog::getHandleCode, 0);
        return this.selectList(wrapper);
    }
}
